"""
集合操作符实现
"""

from typing import Optional, List, Dict, Any, Iterator, Set, Tuple
import time

from ..executor_base import IteratorExecutor
from ..types import Record, RecordBatch, ExecutionContext

class SetOperatorBase(IteratorExecutor):
    """集合操作符基类"""
    
    def __init__(self, executor_id: str, context: ExecutionContext,
                 left_child: IteratorExecutor, right_child: IteratorExecutor):
        super().__init__(executor_id, context)
        self.left_child = left_child
        self.right_child = right_child
        
        # 添加子执行器
        self.add_child(left_child)
        self.add_child(right_child)
    
    def _record_to_tuple(self, record: Record) -> Tuple:
        """将记录转换为可哈希的元组"""
        # 按键排序以确保一致性
        items = []
        for key in sorted(record.keys()):
            value = record[key]
            # 处理不可哈希的值
            if isinstance(value, (list, dict)):
                value = str(value)
            items.append((key, value))
        return tuple(items)
    
    def _tuple_to_record(self, record_tuple: Tuple) -> Record:
        """将元组转换回记录"""
        return dict(record_tuple)
    
    def _load_child_records(self, child: IteratorExecutor) -> Set[Tuple]:
        """加载子执行器的所有记录"""
        records = set()
        
        child.open()
        try:
            while True:
                batch = child.next_batch()
                if not batch:
                    break
                
                for record in batch:
                    self.check_timeout()
                    self.update_stats(rows_processed=1)
                    record_tuple = self._record_to_tuple(record)
                    records.add(record_tuple)
        finally:
            child.close()
        
        return records

class UnionOperator(SetOperatorBase):
    """并集操作符"""
    
    def __init__(self, executor_id: str, context: ExecutionContext,
                 left_child: IteratorExecutor, right_child: IteratorExecutor,
                 distinct: bool = True):
        super().__init__(executor_id, context, left_child, right_child)
        self.distinct = distinct
        self.seen_records: Set[Tuple] = set()
    
    def open(self):
        """打开并集操作符"""
        with self.lock:
            if self.is_open:
                return
            
            self.is_open = True
            self.seen_records.clear()
            
            # 创建并集迭代器
            self.current_iterator = self._create_union_iterator()
    
    def _create_union_iterator(self) -> Iterator[Record]:
        """创建并集迭代器"""
        # 处理左表
        self.left_child.open()
        try:
            while True:
                left_batch = self.left_child.next_batch()
                if not left_batch:
                    break
                
                for record in left_batch:
                    self.check_timeout()
                    self.update_stats(rows_processed=1)
                    
                    if self.distinct:
                        record_tuple = self._record_to_tuple(record)
                        if record_tuple not in self.seen_records:
                            self.seen_records.add(record_tuple)
                            self.update_stats(rows_returned=1)
                            yield record
                    else:
                        self.update_stats(rows_returned=1)
                        yield record
        finally:
            self.left_child.close()
        
        # 处理右表
        self.right_child.open()
        try:
            while True:
                right_batch = self.right_child.next_batch()
                if not right_batch:
                    break
                
                for record in right_batch:
                    self.check_timeout()
                    self.update_stats(rows_processed=1)
                    
                    if self.distinct:
                        record_tuple = self._record_to_tuple(record)
                        if record_tuple not in self.seen_records:
                            self.seen_records.add(record_tuple)
                            self.update_stats(rows_returned=1)
                            yield record
                    else:
                        self.update_stats(rows_returned=1)
                        yield record
        finally:
            self.right_child.close()
    
    def close(self):
        """关闭并集操作符"""
        with self.lock:
            if not self.is_open:
                return
            
            # 清理资源
            self.seen_records.clear()
            
            self.is_open = False
            self.current_iterator = None

class IntersectOperator(SetOperatorBase):
    """交集操作符"""
    
    def __init__(self, executor_id: str, context: ExecutionContext,
                 left_child: IteratorExecutor, right_child: IteratorExecutor,
                 distinct: bool = True):
        super().__init__(executor_id, context, left_child, right_child)
        self.distinct = distinct
        self.right_records: Set[Tuple] = set()
        self.seen_records: Set[Tuple] = set()
    
    def open(self):
        """打开交集操作符"""
        with self.lock:
            if self.is_open:
                return
            
            self.is_open = True
            self.seen_records.clear()
            
            # 预加载右表记录
            self.right_records = self._load_child_records(self.right_child)
            
            # 创建交集迭代器
            self.current_iterator = self._create_intersect_iterator()
    
    def _create_intersect_iterator(self) -> Iterator[Record]:
        """创建交集迭代器"""
        self.left_child.open()
        try:
            while True:
                left_batch = self.left_child.next_batch()
                if not left_batch:
                    break
                
                for record in left_batch:
                    self.check_timeout()
                    self.update_stats(rows_processed=1)
                    
                    record_tuple = self._record_to_tuple(record)
                    
                    # 检查是否在右表中存在
                    if record_tuple in self.right_records:
                        if self.distinct:
                            if record_tuple not in self.seen_records:
                                self.seen_records.add(record_tuple)
                                self.update_stats(rows_returned=1)
                                yield record
                        else:
                            self.update_stats(rows_returned=1)
                            yield record
        finally:
            self.left_child.close()
    
    def close(self):
        """关闭交集操作符"""
        with self.lock:
            if not self.is_open:
                return
            
            # 清理资源
            self.right_records.clear()
            self.seen_records.clear()
            
            self.is_open = False
            self.current_iterator = None

class ExceptOperator(SetOperatorBase):
    """差集操作符（EXCEPT / MINUS）"""
    
    def __init__(self, executor_id: str, context: ExecutionContext,
                 left_child: IteratorExecutor, right_child: IteratorExecutor,
                 distinct: bool = True):
        super().__init__(executor_id, context, left_child, right_child)
        self.distinct = distinct
        self.right_records: Set[Tuple] = set()
        self.seen_records: Set[Tuple] = set()
    
    def open(self):
        """打开差集操作符"""
        with self.lock:
            if self.is_open:
                return
            
            self.is_open = True
            self.seen_records.clear()
            
            # 预加载右表记录
            self.right_records = self._load_child_records(self.right_child)
            
            # 创建差集迭代器
            self.current_iterator = self._create_except_iterator()
    
    def _create_except_iterator(self) -> Iterator[Record]:
        """创建差集迭代器"""
        self.left_child.open()
        try:
            while True:
                left_batch = self.left_child.next_batch()
                if not left_batch:
                    break
                
                for record in left_batch:
                    self.check_timeout()
                    self.update_stats(rows_processed=1)
                    
                    record_tuple = self._record_to_tuple(record)
                    
                    # 检查是否不在右表中
                    if record_tuple not in self.right_records:
                        if self.distinct:
                            if record_tuple not in self.seen_records:
                                self.seen_records.add(record_tuple)
                                self.update_stats(rows_returned=1)
                                yield record
                        else:
                            self.update_stats(rows_returned=1)
                            yield record
        finally:
            self.left_child.close()
    
    def close(self):
        """关闭差集操作符"""
        with self.lock:
            if not self.is_open:
                return
            
            # 清理资源
            self.right_records.clear()
            self.seen_records.clear()
            
            self.is_open = False
            self.current_iterator = None

class UnionAllOperator(UnionOperator):
    """UNION ALL操作符，不去重"""
    
    def __init__(self, executor_id: str, context: ExecutionContext,
                 left_child: IteratorExecutor, right_child: IteratorExecutor):
        super().__init__(executor_id, context, left_child, right_child, distinct=False)

class SymmetricDifferenceOperator(SetOperatorBase):
    """对称差集操作符"""
    
    def __init__(self, executor_id: str, context: ExecutionContext,
                 left_child: IteratorExecutor, right_child: IteratorExecutor):
        super().__init__(executor_id, context, left_child, right_child)
        self.left_records: Set[Tuple] = set()
        self.right_records: Set[Tuple] = set()
    
    def open(self):
        """打开对称差集操作符"""
        with self.lock:
            if self.is_open:
                return
            
            self.is_open = True
            
            # 预加载两个表的记录
            self.left_records = self._load_child_records(self.left_child)
            self.right_records = self._load_child_records(self.right_child)
            
            # 创建对称差集迭代器
            self.current_iterator = self._create_symmetric_diff_iterator()
    
    def _create_symmetric_diff_iterator(self) -> Iterator[Record]:
        """创建对称差集迭代器"""
        # 左表中有但右表中没有的记录
        left_only = self.left_records - self.right_records
        for record_tuple in left_only:
            self.check_timeout()
            self.update_stats(rows_returned=1)
            yield self._tuple_to_record(record_tuple)
        
        # 右表中有但左表中没有的记录
        right_only = self.right_records - self.left_records
        for record_tuple in right_only:
            self.check_timeout()
            self.update_stats(rows_returned=1)
            yield self._tuple_to_record(record_tuple)
    
    def close(self):
        """关闭对称差集操作符"""
        with self.lock:
            if not self.is_open:
                return
            
            # 清理资源
            self.left_records.clear()
            self.right_records.clear()
            
            self.is_open = False
            self.current_iterator = None

class CartesianProductOperator(IteratorExecutor):
    """笛卡尔积操作符"""
    
    def __init__(self, executor_id: str, context: ExecutionContext,
                 left_child: IteratorExecutor, right_child: IteratorExecutor):
        super().__init__(executor_id, context)
        self.left_child = left_child
        self.right_child = right_child
        self.right_records: List[Record] = []
        
        # 添加子执行器
        self.add_child(left_child)
        self.add_child(right_child)
    
    def open(self):
        """打开笛卡尔积操作符"""
        with self.lock:
            if self.is_open:
                return
            
            self.is_open = True
            
            # 预加载右表记录
            self._load_right_records()
            
            # 创建笛卡尔积迭代器
            self.current_iterator = self._create_cartesian_iterator()
    
    def _load_right_records(self):
        """加载右表记录"""
        self.right_child.open()
        try:
            while True:
                right_batch = self.right_child.next_batch()
                if not right_batch:
                    break
                
                self.right_records.extend(right_batch)
                self.update_stats(rows_processed=len(right_batch))
        finally:
            self.right_child.close()
    
    def _create_cartesian_iterator(self) -> Iterator[Record]:
        """创建笛卡尔积迭代器"""
        self.left_child.open()
        try:
            while True:
                left_batch = self.left_child.next_batch()
                if not left_batch:
                    break
                
                for left_record in left_batch:
                    self.check_timeout()
                    
                    for right_record in self.right_records:
                        # 合并记录
                        merged_record = {}
                        
                        # 添加左表记录（加前缀）
                        for key, value in left_record.items():
                            merged_record[f"left.{key}"] = value
                        
                        # 添加右表记录（加前缀）
                        for key, value in right_record.items():
                            merged_record[f"right.{key}"] = value
                        
                        self.update_stats(rows_returned=1)
                        yield merged_record
        finally:
            self.left_child.close()
    
    def close(self):
        """关闭笛卡尔积操作符"""
        with self.lock:
            if not self.is_open:
                return
            
            # 清理资源
            self.right_records.clear()
            
            self.is_open = False
            self.current_iterator = None
    
    def get_estimated_cost(self) -> float:
        """获取估算成本"""
        # 笛卡尔积的成本非常高
        left_rows = getattr(self.left_child, 'get_estimated_rows', lambda: 100)()
        right_rows = getattr(self.right_child, 'get_estimated_rows', lambda: 100)()
        return left_rows * right_rows * 0.1  # 每对记录0.1个成本单位
    
    def get_estimated_rows(self) -> int:
        """获取估算行数"""
        left_rows = getattr(self.left_child, 'get_estimated_rows', lambda: 100)()
        right_rows = getattr(self.right_child, 'get_estimated_rows', lambda: 100)()
        return left_rows * right_rows



